package game;

import gps.GPSEngine;
import gps.GPSNode;
import gps.api.GPSState;

import java.util.Collections;
import java.util.Comparator;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.Set;

public class GridLockEngine extends GPSEngine {

	private int IDlevel = 1;

	@Override
	public void addNode(GPSNode node) {
		switch (strategy) {
		case DFS:
			addNodeDFS(node);
			break;
		case BFS:
			addNodeBFS(node);
			break;
		case ID:
			addNodeID(node);
			break;
		case Astar:
			addNodeAstar(node);
			break;
		case Greedy:
			addNodeGreedy(node);
			break;
		}
	}

	//No borrar esto por que las reglas tienen un puntero a la pieza a la q se aplica
	@Override
	protected boolean explode(GPSNode node) {
		((GridLockProblem) problem).initializeRules(((GridLockState) node
				.getState()).getBoard());
		return super.explode(node);
	};

	private void addNodeDFS(GPSNode node) {
			open.add(0, node);
	}

	private void addNodeBFS(GPSNode node) {
			open.add(node);
	}

	private void addNodeID(GPSNode node) {
			open.add(0, node);
	}

	private void addNodeGreedy(GPSNode node) {
		int index2 = Collections.binarySearch(recentlyExploded, node,
				new Comparator<GPSNode>() {

					@Override
					public int compare(GPSNode o1, GPSNode o2) {
						Integer f1 = problem.getHValue(o1.getState());
						Integer f2 = problem.getHValue(o2.getState());
						if (f1 < f2) {
							return -1;
						} else if (f1 == f2) {
							return 0;
						} else {
							return 1;
						}
					}
				});
		if (index2 >= 0) {
			((LinkedList<GPSNode>) open).add(index2, node);
		} else {
			((LinkedList<GPSNode>) open).add(-1 * (index2 + 1), node);
		}
	}
	
	private void addNodeAstar(GPSNode node) {
		int index = Collections.binarySearch(open, node,
				new Comparator<GPSNode>() {

					@Override
					public int compare(GPSNode o1, GPSNode o2) {
						Integer f1 = o1.getCost()
								+ problem.getHValue(o1.getState());
						Integer f2 = o2.getCost()
								+ problem.getHValue(o2.getState());
						if (f1 < f2) {
							return -1;
						} else if (f1 == f2) {
							return 0;
						} else {
							return 1;
						}
					}
				});
		if (index >= 0) {
			((LinkedList<GPSNode>) open).add(index, node);
		} else {
			((LinkedList<GPSNode>) open).add(-1 * (index + 1), node);
		}
	}
	
	public int getClosedNodesNumber() {
		return this.closed.size();
	}

	public int getTotalNodesNumber() {
		return this.closed.size() + this.open.size();
	}

	public int getTotalBorderNodes() {
		return this.open.size();
	}

	public int getDepth() {
		return this.closed.get(this.closed.size() - 1).getDepth();
	}

	@Override
	public int getIDLevel() {
		return IDlevel;
	}

	@Override
	public void incIDLevel() {
		this.IDlevel++;
	}

}
